package org.duang.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.duang.aop.Interceptor;
import org.duang.config.InstanceFactory;
import org.duang.ioc.Before;
import org.duang.ioc.Ignore;
import org.duang.ioc.Mapping;
import org.duang.kit.ToolsKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author laotang
 */
public final class Routes {
	
	private static Logger logger = LoggerFactory.getLogger(Routes.class);
//	private static Logger logger = LogKit.getLogger(Routes.class);
	public static final Interceptor[] NULL_INTERS = new Interceptor[0];
	private static Map<String, Action> actionMapping = new HashMap<String, Action>();
	private static Map<Class<? extends Interceptor>, Interceptor> intersMap = new HashMap<Class<? extends Interceptor>, Interceptor>();
	
	public static void init(){
		buildRoutes2Action();
	}
	
	/**
	 * Route Mapper to Action
	 */
	public static void buildRoutes2Action() {
		actionMapping.clear();			//保证actionMapping为空		
		Set<String> excludedMethodName = buildExcludedMethodName();
		for(Iterator<Entry<String, Class<? extends Controller>>> it = InstanceFactory.getRoutesMaps().entrySet().iterator(); it.hasNext();){
			Entry<String, Class<? extends Controller>> entry = it.next();
			String controllerKey = entry.getKey();
			Class<? extends Controller> controllerClass = entry.getValue();
			Method[] methods = controllerClass.getMethods();										// Controller里的所有方法
			List<String> controllerMappingKeys = buildControllerMappingKey(controllerKey, controllerClass);		// Controller的映射路径
			if(ToolsKit.isEmpty(controllerMappingKeys)){
				controllerMappingKeys.add(controllerKey);
				controllerMappingKeys.add(controllerKey);
				controllerMappingKeys.add("0");
				controllerMappingKeys.add("");
			}
			for(Method method : methods) {
				String methodName = method.getName();				
				//不存在相同的方法名并且没有参数的方法
				if(!excludedMethodName.contains(methodName) && method.getParameterTypes().length ==0 ) {
					if(method.getAnnotation(Ignore.class) == null ){
						List<String> methodMappingKeys = buildMethodMappingKey(method);							// Method的映射路径					
						String actionKey = controllerMappingKeys.get(0) + methodMappingKeys.get(0);				// 映射路径, 全小写
						String descKey = controllerMappingKeys.get(1) + methodMappingKeys.get(1);
						String levelKey = methodMappingKeys.get(2);
						String orderKey = methodMappingKeys.get(3);
//						boolean isExistInterceptor = isExistInterceptor(method);								// 检查是否有拦截器
//						Action action = isExistInterceptor ? new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method, InstanceFactory.getInterceptor())
//													  : new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method);
						
						Action action = new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method, buildMethodInterceptors(method));
						
						if(!ToolsKit.isExist(actionKey, actionMapping)){
							actionMapping.put(actionKey, action);
						}
					}
					
					//如果方法名为index的增加一个去掉index的URL映射
					if("index".equalsIgnoreCase(methodName)){
						String actionKey = controllerMappingKeys.get(0);
						String descKey = controllerMappingKeys.get(1);
						String levelKey = controllerMappingKeys.get(2);
						String orderKey = controllerMappingKeys.get(3);
//						boolean isExistInterceptor = isExistInterceptor(method);			
//						Action action = isExistInterceptor ? new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method, InstanceFactory.getInterceptor())
//						  							: new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method);
						Action action = new Action(actionKey, descKey, levelKey, orderKey, controllerClass, method, buildMethodInterceptors(method));
						if(!ToolsKit.isExist(actionKey, actionMapping)){
							actionMapping.put(actionKey, action);
						}
					}
				}
			}
		}
		
		Action actoin = actionMapping.get("/");
		if (actoin == null) actoin = new Action();
		actionMapping.put("", actoin);
		
		List<String> keyList = getAllActionKeys();
		logger.warn("**************** All Controller Mapper Key ****************");
		for (String key : keyList) {
			if(!"".equals(key)) logger.warn(key);
//			if(!"".equals(key)) logger.warn(key +"-------------"+ actionMapping.get(key).getDescKey()+"-------------"+ actionMapping.get(key).getLevelKey());
		}
		
		if(!actionMapping.isEmpty()){
			InstanceFactory.setActionMapping(actionMapping);
		}
	}
	
	/**
	 * 只能参数长度为0的方法,即取没有参数的方法
	 * @return
	 */
	private static Set<String> buildExcludedMethodName() {
		Set<String> excludedMethodName = new HashSet<String>();
		Method[] methods = Controller.class.getMethods();
		
		if(null != methods){
			for (Method method : methods) {
				//参数长度为0的方法名				
				if(method.getParameterTypes().length == 0){
					if(method.getAnnotation(Ignore.class) == null){
						excludedMethodName.add(method.getName().trim());
					}
				}
			}
		}
		return excludedMethodName;
	}
	
	private static List<String> buildControllerMappingKey(String controllerKey, Class<? extends Controller> controllerClass){
		Mapping controllerMapping = controllerClass.getAnnotation(Mapping.class);			
		List<String> result = new ArrayList<String>();
		if(null != controllerMapping){
			String value = controllerMapping.value();
			value = value.endsWith("/") ? value.substring(0, value.length()-1) : value;
			value = value.startsWith("/") ? value : "/" + value;
			value = ToolsKit.toLowerCase(value);
			
			String desc = controllerMapping.desc();
			desc = desc.endsWith("/") ? desc.substring(0, desc.length()-1) : desc;
			desc = desc.startsWith("/") ? desc : "/"+desc;	
			
			if("/".equals(value) || ToolsKit.isEmpty(value)) value = controllerKey;
			if(ToolsKit.isEmpty(desc)) desc = value;
			result.add(value);
			result.add(desc);
			result.add(controllerMapping.level()+"");
			result.add(controllerMapping.order());
		} 
		return result;
	}
	
	private static List<String> buildMethodMappingKey(Method method){
		Mapping methodMapping = method.getAnnotation(Mapping.class);
		String value = "", desc = "", order= "";
		int level = 0;
		if(null != methodMapping){
			value = methodMapping.value();
			value = value.endsWith("/") ? value.substring(0, value.length()-1) : value;
			value = value.startsWith("/") ? value : "/"+value;	
			
			desc = methodMapping.desc();
			desc = desc.endsWith("/") ? desc.substring(0, desc.length()-1) : desc;
			desc = desc.startsWith("/") ? desc : "/"+desc;
			
			level = methodMapping.level();
			order = methodMapping.order();
		} 
		if("/".equals(value) || ToolsKit.isEmpty(value)) value = "/" + method.getName();
		if(ToolsKit.isEmpty(desc)) desc = value;
		List<String> result = new ArrayList<String>();
		result.add(ToolsKit.toLowerCase(value));
		result.add(desc);
		result.add(level+"");
		result.add(order);
		return result;
	}
	
	private static List<String> getAllActionKeys() {
		List<String> allActionKeys = new ArrayList<String>(actionMapping.keySet());
		Collections.sort(allActionKeys);
		return allActionKeys;
	}
	
//	private static boolean isExistInterceptor(Method method) {
//		Annotation[] ats = method.getAnnotations();
//		if(null != ats && ats.length > 0){
//			for(int i=0; i<ats.length; i++){
//				if(!ats[i].annotationType().equals(Mapping.class)){
//					return true;
//				}
//			}
//		}
//		return false;
//	}
	
	
	private static Interceptor[] buildMethodInterceptors(Method method) {
		Before beforeAnnotation = method.getAnnotation(Before.class);
		if (beforeAnnotation == null)
			return NULL_INTERS;
		
		Class<? extends Interceptor>[] interceptorClasses = beforeAnnotation.value();
		if (interceptorClasses.length == 0)
			return NULL_INTERS;
		
		Interceptor[] result = new Interceptor[interceptorClasses.length];
		try {
			for (int i=0; i<result.length; i++) {
				result[i] = intersMap.get(interceptorClasses[i]);
				if (result[i] == null) {
					result[i] = (Interceptor)interceptorClasses[i].newInstance();
					intersMap.put(interceptorClasses[i], result[i]);
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return result;
	}
}
